/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package vn.passbookviet.bean;

import com.ryantenney.passkit4j.Pass;
import com.ryantenney.passkit4j.PassResource;
import com.ryantenney.passkit4j.PassSerializer;
import com.ryantenney.passkit4j.model.Color;
import com.ryantenney.passkit4j.model.Generic;
import com.ryantenney.passkit4j.model.TextField;
import com.ryantenney.passkit4j.sign.PassSigner;
import com.ryantenney.passkit4j.sign.PassSignerImpl;
import com.ryantenney.passkit4j.sign.PassSigningException;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.Serializable;
import java.security.KeyPair;
import java.security.NoSuchProviderException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Random;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.ViewScoped;
import javax.faces.event.ActionEvent;
import org.bouncycastle.openssl.PEMReader;
import org.bouncycastle.openssl.PasswordFinder;
import vn.passbookviet.ultilities.JSFUtilities;

/**
 *
 * @author Bach
 */
@ManagedBean
@ViewScoped
public class beanGenerate implements Serializable {

    @ManagedProperty(value = "#{beanSaveData}")
    private beanSaveData applicationManager;
    //
    private static final String PASS_CONTENT_TYPE = "application/vnd.apple.pkpass";
    private static final String PASS_FILE_NAME = "Pass";
    //

    public beanGenerate() {
    }

    public beanSaveData getApplicationManager() {
        return applicationManager;
    }

    public void setApplicationManager(beanSaveData applicationManager) {
        this.applicationManager = applicationManager;
    }
    //
    private boolean isGenerated = false;
    private String fileName;
    //private String logo;
    private String logoText;
    private String headerField;
    private String primaryFields;
//    private String thumbnail
    private String secondaryFields;
    private String auxiliaryFields;
    //
    // <editor-fold>

    public String getLogoText() {
        return logoText;
    }

    public void setLogoText(String logoText) {
        this.logoText = logoText;
    }

    public String getHeaderField() {
        return headerField;
    }

    public void setHeaderField(String headerField) {
        this.headerField = headerField;
    }

    public String getPrimaryFields() {
        return primaryFields;
    }

    public void setPrimaryFields(String primaryFields) {
        this.primaryFields = primaryFields;
    }

    public String getSecondaryFields() {
        return secondaryFields;
    }

    public void setSecondaryFields(String secondaryFields) {
        this.secondaryFields = secondaryFields;
    }

    public String getAuxiliaryFields() {
        return auxiliaryFields;
    }

    public void setAuxiliaryFields(String auxiliaryFields) {
        this.auxiliaryFields = auxiliaryFields;
    }

    public boolean isIsGenerated() {
        System.out.println("Get isGenerated: " + isGenerated);
        return isGenerated;
    }

    public void setIsGenerated(boolean isGenerated) {
        this.isGenerated = isGenerated;
    }
// </editor-fold>
    //
    //

    public void doGenerate(ActionEvent event) {
        isGenerated = false;
        try {
            byte[] data = generateCard(
                    this.logoText, this.headerField, this.primaryFields, this.secondaryFields, this.auxiliaryFields);

            fileName = applicationManager.getNewPassName();
            File f = new File(JSFUtilities.getAbsoluatePath("/temp/"), fileName);
            f.createNewFile();
            FileOutputStream fos = new FileOutputStream(f);
            fos.write(data);
            fos.close();
            System.out.println("Wrote pass to: " + f.getAbsolutePath());
            isGenerated = true;
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        System.out.println("Is Generated = " + isGenerated);
    }

    public String getFileName() {
        return fileName;
    }

    public void setFileName(String fileName) {
        this.fileName = fileName;
    }

    private byte[] generateCard(
            String logoText, String headerFields, String primaryFields, String secondaryFields, String auxiliaryFields)
            throws FileNotFoundException, CertificateException, NoSuchProviderException, IOException, PassSigningException {
        File fResourceFolder = new File(JSFUtilities.getAbsoluatePath("/resources/"));
        System.out.println("Path: " + fResourceFolder.getAbsolutePath());
        if (!fResourceFolder.exists()) {
            System.out.println("Folder Resource not exist !");
            return null;
        }
        File fStoreCardFolder = new File(fResourceFolder, "storecard");
        File fCerFolder = new File(fResourceFolder, "certificate");

        Pass pass = new Pass()
                .teamIdentifier("team-identifier")
                .passTypeIdentifier("pass.com.bouldercoffeeco.storeCard")
                .organizationName("Boulder Coffee Co.")
                .description("Boulder Coffee Rewards Card Example")
                .serialNumber("p69f2J")
                .logoText(logoText)
                .foregroundColor(Color.WHITE)
                .backgroundColor(new Color(118, 74, 50));

        System.out.println("String primaryFields = \"" + primaryFields + "\";");
        System.out.println("String headerFields = \"" + headerFields + "\";");
        System.out.println("String auxiliaryFields = \"" + auxiliaryFields + "\";");
        System.out.println("String secondaryFields = \"" + secondaryFields + "\";");

        Generic generic = new Generic();
        TextField[] arrTxtFiled = getTextField(primaryFields);
        if (arrTxtFiled != null) {
            generic.primaryFields(arrTxtFiled);
        }
        //
        arrTxtFiled = getTextField(auxiliaryFields);
        if (arrTxtFiled != null) {
            generic.auxiliaryFields(getTextField(auxiliaryFields));
        }
        //
        arrTxtFiled = getTextField(headerFields);
        if (arrTxtFiled != null) {
            generic.headerFields(getTextField(secondaryFields));
        }
        //
        if (arrTxtFiled != null) {
            generic.secondaryFields(arrTxtFiled);
        }
        //

        pass.passInformation(generic);

        {
            File[] arrFileRes = fStoreCardFolder.listFiles();
            PassResource[] arrRes = new PassResource[arrFileRes.length];
            for (int i = 0; i < arrFileRes.length; i++) {
                arrRes[i] = new PassResource(arrFileRes[i].getName(), arrFileRes[i]);
            }
            pass.files(arrRes);
        }
        //<editor-fold>
        PassSignerImpl.Builder builder = PassSignerImpl.builder();
        System.out.println("cerFile exist = " + new File(fCerFolder, "AppleWWDRCA.cer").exists());

        builder.intermediateCertificate(
                new FileInputStream(new File(fCerFolder, "AppleWWDRCA.cer")));

        {
            File fPrivateKeyFile = new File(fCerFolder, "exported-key");
            BufferedReader br = new BufferedReader(new FileReader(fPrivateKeyFile));
            KeyPair kp = (KeyPair) new PEMReader(br, new PasswordFinder() {
                @Override
                public char[] getPassword() {
                    return "1234".toCharArray();
                }
            }).readObject();
            builder.privateKey(kp.getPrivate());
        }

        {
            File fSigningCertificate = new File(fCerFolder, "exported-cer");
            CertificateFactory factory = CertificateFactory.getInstance("X.509");
            X509Certificate certificate = (X509Certificate) factory.generateCertificate(new FileInputStream(fSigningCertificate));
            builder.signingCertificate(certificate);
        }
        //</editor-fold>
        PassSigner signer = builder.build();

        System.out.println(
                "Signing...");
        ByteArrayOutputStream bos = new ByteArrayOutputStream();

        PassSerializer.writePkPassArchive(pass, signer, bos);

        System.out.println(
                "Done !");

        return bos.toByteArray();
    }

    public static String getRandomToken() {
        StringBuilder sb = new StringBuilder();
        Random r = new Random();
        for (int i = 0; i < 16; i++) {
            sb.append(r.nextInt(10));
        }
        return sb.toString();
    }

    private TextField[] getTextField(String input) {
        if (input == null || input.isEmpty()) {
            return null;
        }
        ArrayList<TextField> arrList = new ArrayList<TextField>();
        String[] arrInput = input.split("\n");
        for (String str : arrInput) {
            str = str.trim();
            int i = str.indexOf(':');
            if (i <= 0) {
                i = 0;
                arrList.add(new TextField(getRandomToken(), "", str.substring(i)));
            } else {
                String[] a = str.split(":");
                arrList.add(new TextField(getRandomToken(), a[0], a[1]));
            }
        }
        return arrList.toArray(ARR_EMPTY);
    }
    private static final TextField[] ARR_EMPTY = new TextField[0];

    public String getFullPathPass() {
        return beanSaveData.WEB_URL + getFileName();
    }
}
